﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace statistics
{
    public class Stats
    {
        public static double GetAverage(double[] data)
        {
            int len = data.Length;

            if (len == 0)
                throw new Exception("No data");

            double sum = 0;

            for (int i = 0; i < data.Length; i++)
                sum += data[i];

            return sum / len;
        }


        /// <summary>
        /// Get variance
        /// </summary>
        public static double GetVariance(double[] data)
        {
            int len = data.Length;

            // Get average
            double avg = GetAverage(data);

            double sum = 0;

            for (int i = 0; i < data.Length; i++)
                sum += Math.Pow((data[i] - avg), 2);

            return sum / len;
        }

        /// <summary>
        /// Get standard deviation
        /// </summary>
        public static double GetStdev(double[] data)
        {
            return Math.Sqrt(GetVariance(data));
        }

        /// <summary>
        /// Get correlation
        /// </summary>
        public static double GetCorrelation(double[] x, double[] y)
        {
            double covXY=0;
            double correlXY;
            if (x.Length != y.Length)
                throw new Exception("Length of sources is different");

            double avgX = GetAverage(x);
            double stdevX = GetStdev(x);
            double avgY = GetAverage(y);
            double stdevY = GetStdev(y);
            int len = x.Length;
            for (int i = 0; i < len; i++)
                covXY += (x[i] - avgX) * (y[i] - avgY);
            covXY /= len;
            correlXY = covXY / (stdevX * stdevY);
            return correlXY;
        }
        public static double GetCovariance(double[] x, double[] y)
        {
            double covXY=0;
            if (x.Length != y.Length)
                throw new Exception("Length of sources is different");
            double avgX = GetAverage(x);
            double stdevX = GetStdev(x);
            double avgY = GetAverage(y);
            double stdevY = GetStdev(y);
            int len = x.Length;
            for (int i = 0; i < len; i++)
                covXY += (x[i] - avgX) * (y[i] - avgY);
            covXY /= len;
            return covXY;
        }
        public static double NormInv(double Probability, double Mu, double Sigma)
        {
            double x = 0; ;
            double p;
            double c0;
            double c1;
            double c2;
            double d1;
            double d2;
            double d3;
            double t;
            double q;
            double result;
            q = Probability;
            if ((q == 0.5))
            {
                result = Mu;
            }
            else
            {
                q = (1 - q);
                // #
                if (((q > 0)
                            && (q < 0.5)))
                {
                    p = q;
                }
                else if ((q == 1))
                {
                    p = (1 - 0.9999999);
                    //  JPR - attempt to fix divide by zero below, what is NormInv(1,x,y)?
                }
                else
                {
                    p = (1 - q);
                    // #
                }
                t = Math.Sqrt(Math.Log((1 / (p * p))));
                // #
                c0 = 2.515517;
                c1 = 0.802853;
                c2 = 0.010328;
                d1 = 1.432788;
                d2 = 0.189269;
                d3 = 0.001308;
                x = (t - ((c0 + ((c1 * t) + (c2 * (t * t))))
                    / (1 + ((d1 * t) + ((d2 * (t * t)) + (d3 * (Math.Pow(t, 3))))))));
                // TODO: Warning!!! The operator should be an XOR ^ instead of an OR, but not available in CodeDOM
                if ((q > 0.5))
                {
                    x = ((1 * x)
                                * -1);
                    // #
                }
                result = (x * Sigma) + Mu;
            }
            return result;
        }
    }

}
